//==================================================================
//  Copyright (C) 2006-2007  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
/// @file	m5d_verts.h
///
/// @brief	Vertices types.
///
//==================================================================

#ifndef M5D_VERTS_H
#define M5D_VERTS_H

#include <vector>
#include "psys.h"
#include "psys_stdgfx.h"
#include "pvector.h"
#include "m5d_types.h"

//==================================================================
namespace M5D {

//==================================================================
/// Vertices with multiple, separate properties.
//==================================================================
class MultiVerts : public PSYS::sync_obj
{
private:
	std::vector<PMath::Vector3>		_pos_vertsp;
	std::vector<PMath::Vector2>		_tex_vertsp;
	std::vector<PSYSGFX::Color4b>	_col_vertsp;
	std::vector<PMath::Vector3>		_nor_vertsp;
	std::vector<float>				_wei_vertsp;	// maxbone * _pos_vertsp.len()
	std::vector<u_char>				_bni_vertsp;	// maxbone * _pos_vertsp.len()
	int							_max_bones_per_vertex;

public:
	//--------------------------------------------------------------
	MultiVerts() :
		_max_bones_per_vertex(0)
	{
	}

	~MultiVerts()
	{
	}

	//--------------------------------------------------------------

public:
	void					SetWeightsMax( int max_weights_per_vertex )	 throw(...);
	u_int					GetWeightsMax() const
	{
		return _max_bones_per_vertex;
	}

	PMath::Vector3			*AddPosN( int add_n );
	PMath::Vector2			*AddTexN( int add_n );
	PSYSGFX::Color4b		*AddColN( int add_n );
	PMath::Vector3			*AddNorN( int add_n );
	// weights		-- depends on position count
	// used bones	-- depends on position count

	void	SetPosN( int set_n );
	void	SetTexN( int set_n );
	void	SetColN( int set_n );
	void	SetNorN( int set_n );
	// weights		-- depends on position count
	// used bones	-- depends on position count

	//PMath::Vector3			*GetPos()		{ AssertLockW();	return &_pos_vertsp.front(); };
	//const PMath::Vector3	*GetPos() const { AssertLockR();	return &_pos_vertsp.front(); };
	PMath::Vector3			*GetPosW()		{ AssertLockW();	return &_pos_vertsp.front(); };
	const PMath::Vector3	*GetPosR() const { AssertLockR();	return &_pos_vertsp.front(); };

	PMath::Vector2			*GetTexW()			{ AssertLockW();	return &_tex_vertsp.front(); };
	const PMath::Vector2	*GetTexR() const	{ AssertLockR();	return &_tex_vertsp.front(); };
	PSYSGFX::Color4b		*GetColW()			{ AssertLockW();	return &_col_vertsp.front(); };
	const PSYSGFX::Color4b	*GetColR() const	{ AssertLockR();	return &_col_vertsp.front(); };
	PMath::Vector3			*GetNorW()			{ AssertLockW();	return &_nor_vertsp.front(); };
	const PMath::Vector3	*GetNorR() const	{ AssertLockR();	return &_nor_vertsp.front(); };
	const float				*GetWeiR() const;		// separate processing, because it may need to allocate on the fly..
	float					*GetWeiW();		// separate processing, because it may need to allocate on the fly..
	const u_char			*GetBNLR() const;
	u_char					*GetBNLW();

	int						GetPosN() const	{ return _pos_vertsp.size(); };
	int						GetTexN() const	{ return _tex_vertsp.size(); };
	int						GetColN() const	{ return _col_vertsp.size(); };
	int						GetNorN() const	{ return _nor_vertsp.size(); };

	void					TransPos( const int *tablep ) throw(...);

	void					CopyFrom( const MultiVerts &src ) throw(...);

public:
	void onChange()		{	_revcnt += 1;	}

	friend class Mesh;
};

//==================================================================
/// Pack vertices types used in display-lists.
//==================================================================
namespace PackVert
{
	//==================================================================
	enum Type
	{
		TYPE_ANY = 0,
		TYPE_POSCOLTEXNOR,
		TYPE_POSTEXCOL,
		TYPE_POSTEXNOR,
		TYPE_POSCOLNOR,
		TYPE_POSTEX,
		TYPE_POSCOL,
		TYPE_POSNOR,
		TYPE_POS,

		TYPE_TOTAL
	};

	//==================================================================
	struct PosTexColNor
	{
		PMath::Vector3		pos;
		PMath::Vector2		tex;
		PSYSGFX::Color4b	col;
		PMath::Vector3		nor;
	};

	struct PosTexCol
	{
		PMath::Vector3		pos;
		PMath::Vector2		tex;
		PSYSGFX::Color4b	col;
	};

	struct PosTexNor
	{
		PMath::Vector3		pos;
		PMath::Vector2		tex;
		PMath::Vector3		nor;
	};

	struct PosColNor
	{
		PMath::Vector3		pos;
		PSYSGFX::Color4b	col;
		PMath::Vector3		nor;
	};

	struct PosTex
	{
		PMath::Vector3		pos;
		PMath::Vector2		tex;
	};

	struct PosCol
	{
		PMath::Vector3		pos;
		PSYSGFX::Color4b	col;
	};

	struct PosNor
	{
		PMath::Vector3		pos;
		PMath::Vector3		nor;
	};

	struct Pos
	{
		PMath::Vector3		pos;
	};

};

};

#endif
